/*
 *	Copyright (c) 2006 Marcus Fuhrmeister <marcus.fuhrmeister@xemail.de>
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; either version 2 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program; if not, write to the Free Software
 *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
 */

package de.fuhrmeister.util;

import java.awt.Image;
import java.awt.Toolkit;
import java.io.File;
import java.lang.reflect.Method;
import java.util.Hashtable;

import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.UIManager;
import javax.swing.filechooser.FileSystemView;

import sun.awt.shell.ShellFolder;

/**
 * Image manager handling application pending image manipulation to
 * create, scale or get system icon of file.
 * 
 * @date	17.02.2012
 * @author	Marcus Fuhrmeister
 */
public class ImageManager {

	private Image image;
	private Hashtable<String, Image> imageHash;
	private static ImageManager imageMng;

	public static String APPLICATION = "application";
	public static String SPLASH = "splash";

	/**
	 * Singleton pattern.
	 * 
	 * @return this
	 */
	public static synchronized ImageManager getInstance() {
		if (imageMng == null) {
			ImageManager.imageMng = new ImageManager();
			return ImageManager.imageMng;
		}
		return ImageManager.imageMng;
	}

	/**
	 * Constructor, calling to init the image hash table.
	 */
	public ImageManager() {
		super();
		initHashtable();
	}

	/**
	 * Inits the image hash table.
	 */
	private void initHashtable() {
		imageHash = new Hashtable<String, Image>(4);
		imageHash.put("splash", getImageForHash("splash.png"));
		imageHash.put("application", getImageForHash("application.png"));
		imageHash.put("options_active", getImageForHash("options_active.png"));
		imageHash.put("options_inactive", getImageForHash("options_inactive.png"));
	}

	/**
	 * Returns an image stored in the file with the given path.
	 * 
	 * @param newPath
	 *            the path to the image file.
	 * @return the loaded image
	 */
	public Image getImageForHash(final String newPath) {
		image = Toolkit.getDefaultToolkit().getImage(this.getClass().getClassLoader().getResource(newPath));
		return image;
	}

	/**
	 * Returns an image icon based on the image that is stored in the hash table with the
	 * given key.
	 * 
	 * @param key
	 *            the key for the image stored in the hash table
	 * @return the new image icon
	 */
	public ImageIcon getIcon(final String key) {
		return new ImageIcon(getImage(key));
	}

	/**
	 * Returns an image stored in the hash table with the given key.
	 * 
	 * @param key
	 *            the key for the image stored in the hash table
	 * @return the image in the hash table
	 */
	public Image getImage(final String key) {
		return imageHash.get(key);
	}

	/**
	 * Calls to scale the given icon to the given size.
	 * 
	 * @param icon the icon to scale
	 * @param size the new size for the icon
	 * @return the scaled icon
	 */
	public Icon scaleIcon(final Icon icon, final int size) {
		return scaleIcon(icon, size, size);

	}

	/**
	 * Scales the given icon to the given width and height.
	 * 
	 * @param icon the icon to scale
	 * @param width the new width for the icon
	 * @param height the new height for the icon
	 * @return the scaled icon
	 */
	public Icon scaleIcon(final Icon icon, final int width, final int height) {
		return new ImageIcon(((ImageIcon) icon).getImage().getScaledInstance(width, height, Image.SCALE_SMOOTH));
	}

	/**
	 * Scales the given image icon to the given width and height.
	 * 
	 * @param icon the image icon to scale
	 * @param width the new width for the image icon
	 * @param height the new height for the image icon
	 * @return the scaled image icon
	 */
	public ImageIcon scaleIcon(final ImageIcon icon, final int width, final int height) {
		return new ImageIcon(icon.getImage().getScaledInstance(width, height, Image.SCALE_SMOOTH));
	}

	/**
	 * Scales the given image to the given width and height.
	 * 
	 * @param image the image to scale
	 * @param width the new width for the image
	 * @param height the new height for the image
	 * @return the scaled image
	 */
	public Image scaleImage(final Image image, final int width, final int height) {
		return image.getScaledInstance(width, height, Image.SCALE_SMOOTH);
	}

	/**
	 * Returns an icon for the given icon path.
	 * If the path does not exist, the system icon representing the
	 * given executable <code>exec</code> is used instead.
	 * Otherwise the build in application icon is used.
	 * 
	 * @param icon
	 *            the path to an icon
	 * @param size
	 *            the size of the icon to be scaled to
	 * @param exec
	 *            the path to an executable
	 * 
	 * @return Icon the extracted icon
	 */
	public Icon createIcon(final String icon, final int size, final String exec) {
		ImageIcon ico = null;
		if (icon != null && icon != "") {
			try {
				ico = new ImageIcon(icon);
			} catch (final Exception e) {
				return this.scaleIcon(this.getIcon("application"), size, size);
			}
		} else if (exec != null && exec != "") {
			try {
				final File execFile = new File(exec);
				if (execFile.exists()) {
					ico = this.getSystemIcon(execFile);
				} else {
					ico = null;
				}
			} catch (final Exception e) {
				return this.scaleIcon(this.getIcon("application"), size, size);
			}
		}
		if (ico != null) {
			return this.scaleIcon(ico, size, size);
		} else {
			return this.scaleIcon(this.getIcon("application"), size, size);
		}
	}

	/**
	 * Returns the system icon for the given file.
	 * 
	 * @param f the file the system icon needs to be found.
	 * @return the system pending image icon of the file, the default folder or file icon or null
	 * @throws Exception
	 */
	public ImageIcon getSystemIcon(final File f) throws Exception {
		if (f != null) {
			final Class<FileSystemView> fsv = FileSystemView.class;
			try {
				final Method m = fsv.getDeclaredMethod("getShellFolder", new Class[] { File.class });
				m.setAccessible(true);
				final ShellFolder sf = (ShellFolder) m.invoke(FileSystemView.getFileSystemView(), f);
				final Image img = sf.getIcon(true);
				if (img != null) {
					return new ImageIcon(img, sf.getFolderType());
				} else {
					return (ImageIcon) UIManager.getIcon(f.isDirectory() ? "FileView.directoryIcon" : "FileView.fileIcon");
				}
			} catch (final java.lang.NullPointerException e) {
				throw new java.lang.NullPointerException();
			}
		}
		return null;
	}
}
